﻿using System;
using System.IO;
using System.Windows.Forms;

namespace VisualPureBasicIDE.CoreGUI.SolutionManager
{
    public class SolutionTreeView : TreeView
    {
        #region Members

        private string _previousName;
        private bool _showHiddenFiles = true;

        #endregion

        #region Properties

        /// <summary>
        /// Get or set visibility of hidden files on the tree
        /// </summary>
        public bool ShowHiddenFiles
        {
            get { return _showHiddenFiles; }
            set { _showHiddenFiles = value; }
        }

        #endregion

        #region Constructor

        public SolutionTreeView()
        {
            LabelEdit = true;
            BeforeLabelEdit += SolutionTreeView_BeforeLabelEdit;
            AfterLabelEdit += SolutionTreeView_AfterLabelEdit;
            NodeMouseClick += SolutionTreeView_NodeMouseClick;
            NodeMouseDoubleClick += SolutionTreeView_NodeMouseDoubleClick;
        }

        private void SolutionTreeView_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            if (e.Node != null && e.Node is SolutionTreeNode)
            {
                var node = e.Node as SolutionTreeNode;
                _previousName = node.Text;
            }
        }

        private void SolutionTreeView_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            if (e.Node != null && e.Node is SolutionTreeNode && !string.IsNullOrEmpty(_previousName))
            {
                var node = e.Node as SolutionTreeNode;
                if (node.Path != null && node.Path.Contains(_previousName) && !string.IsNullOrEmpty(e.Label))
                {
                    //TODO: Disable FileSystemWatcher

                    try
                    {
                        var before = node.Path;
                        var after = node.Path.Replace(_previousName, e.Label);
                        File.Move(before, after);
                        node.Path = after;
                    }
                    catch
                    {
                        e.CancelEdit = true;
                        node.Text = _previousName;
                    }

                    //TODO: Enable FileSystemWatcher
                }
            }
        }

        #endregion

        #region Methods

        public void Action(SolutionTreeViewActions action, SolutionTreeNode node)
        {
            switch (action)
            {
                case SolutionTreeViewActions.ExcludeFromProject:
                    node.IsIncluded = false;
                    RefreshSubnodes(node);
                    break;

                case SolutionTreeViewActions.IncludeInProject:
                    node.IsIncluded = true;
                    RefreshSubnodes(node);
                    break;

                case SolutionTreeViewActions.Rename:
                    node.BeginEdit();
                    break;
            }

            var args = new SolutionActionEventArgs {Action = action, Node = node};
            OnActionRequest(this, args);
        }

        public void RefreshSubnodes(SolutionTreeNode node)
        {
            if (node == null) return;

            if (!_showHiddenFiles && !node.IsIncluded)
            {
                node.Remove();
                return;
            }

            switch (node.Type)
            {
                case SolutionTreeNodeTypes.File:
                    if (node.IsIncluded)
                    {
                        if (File.Exists(node.Path))
                        {
                            node.ImageIndex = node.GetIconIndex(node.Path);
                            node.SelectedImageIndex = node.GetIconIndex(node.Path);
                        }
                        else
                        {
                            node.Icon = TreeIcons.FileBroken;
                        }
                    }
                    else
                    {
                        node.Icon = TreeIcons.FileHidden;
                    }
                    break;

                case SolutionTreeNodeTypes.Folder:
                    if (_showHiddenFiles && Directory.Exists(node.Path))
                    {
                        //Get files
                        var files = Directory.GetFiles(node.Path);
                        foreach (var file in files)
                        {
                            var contains = false;
                            foreach (SolutionTreeNode item in node.Nodes)
                            {
                                if (item.Path == file)
                                {
                                    contains = true;
                                    break;
                                }
                            }
                            if (!contains)
                            {
                                var text = Path.GetFileName(file);
                                var solutionTreeNode = new SolutionTreeNode(text, SolutionTreeNodeTypes.File, file,
                                                                            TreeIcons.FileHidden) {IsIncluded = false};
                                node.Nodes.Add(solutionTreeNode);
                            }
                        }

                        //Get folders
                        var folders = Directory.GetDirectories(node.Path);
                        foreach (var folder in folders)
                        {
                            var contains = false;
                            foreach (SolutionTreeNode item in node.Nodes)
                            {
                                if (item.Path == folder)
                                {
                                    contains = true;
                                    break;
                                }
                            }
                            if (!contains)
                            {
                                var pos = folder.LastIndexOf('\\');
                                if (pos > 0)
                                {
                                    var text = folder.Substring(pos + 1);
                                    var solutionTreeNode = new SolutionTreeNode(text, SolutionTreeNodeTypes.Folder,
                                                                                folder, TreeIcons.FolderHiddenClosed)
                                                               {IsIncluded = false};
                                    node.Nodes.Insert(0, solutionTreeNode);
                                }
                            }
                        }
                    }

                    foreach (SolutionTreeNode subnode in node.Nodes)
                    {
                        RefreshSubnodes(subnode);
                    }
                    break;

                case SolutionTreeNodeTypes.Solution:
                case SolutionTreeNodeTypes.Project:
                case SolutionTreeNodeTypes.VirtualFolder:
                    foreach (SolutionTreeNode subnode in node.Nodes)
                    {
                        RefreshSubnodes(subnode);
                    }
                    break;
            }
        }

        #endregion

        #region Events

        protected void SolutionTreeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node != null && e.Node is SolutionTreeNode)
            {
                var node = e.Node as SolutionTreeNode;
                SelectedNode = node;

                #region Right-click

                if (e.Button == MouseButtons.Right && ContextMenuStrip != null &&
                    node.Type != SolutionTreeNodeTypes.Unknown)
                {
                    foreach (ToolStripItem menuItem in ContextMenuStrip.Items)
                    {
                        var isVisible = false;
                        switch (menuItem.Name)
                        {
                            case "toolStripSeparator2":
                                if (node.Type == SolutionTreeNodeTypes.Solution ||
                                    node.Type == SolutionTreeNodeTypes.Project ||
                                    node.Type == SolutionTreeNodeTypes.Folder ||
                                    node.Type == SolutionTreeNodeTypes.File)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "toolStripSeparator3":
                                if (node.Type == SolutionTreeNodeTypes.VirtualFolder ||
                                    node.Type == SolutionTreeNodeTypes.File)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "toolStripSeparator4":
                                if (node.Type == SolutionTreeNodeTypes.Folder)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "toolStripSeparator5":
                            case "toolStripSeparator6":
                                isVisible = true;
                                break;

                            case "toolStripSeparator1":
                            case "buildToolStripMenuItem":
                            case "rebuildToolStripMenuItem":
                            case "cleanToolStripMenuItem":
                            case "debugToolStripMenuItem":
                                if (node.Type == SolutionTreeNodeTypes.Solution ||
                                    node.Type == SolutionTreeNodeTypes.Project)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "addItemToolStripMenuItem":
                                if (node.Type == SolutionTreeNodeTypes.Project ||
                                    node.Type == SolutionTreeNodeTypes.Folder)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "addProjectToolStripMenuItem":
                                if (node.Type == SolutionTreeNodeTypes.Solution ||
                                    node.Type == SolutionTreeNodeTypes.VirtualFolder)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "openToolStripMenuItem":
                            case "openWithToolStripMenuItem":
                                if (node.Type == SolutionTreeNodeTypes.File)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "viewCodeToolStripMenuItem":
                            case "viewDesignerToolStripMenuItem":
                                if (node.Type == SolutionTreeNodeTypes.File)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "includeInProjectToolStripMenuItem":
                                if (!node.IsIncluded)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "excludeFromProjectToolStripMenuItem":
                                if (node.IsIncluded)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "openFolderInWindowsExplorerToolStripMenuItem":
                                if (node.Type == SolutionTreeNodeTypes.Folder)
                                {
                                    isVisible = true;
                                }
                                break;

                            case "renameToolStripMenuItem":
                            case "propertiesToolStripMenuItem":
                                isVisible = true;
                                break;
                        }
                        menuItem.Visible = isVisible;
                    }
                }

                #endregion

                //if (e.Button == MouseButtons.Left)
                //{
                //    switch (node.Type)
                //    {
                //        case SolutionTreeNodeTypes.Folder:
                //            if (node.IsExpanded)
                //            {
                //                node.ImageIndex = (int)TreeIcons.FolderOpened;
                //                node.SelectedImageIndex = (int)TreeIcons.FolderOpened;
                //            }
                //            else
                //            {
                //                node.ImageIndex = (int)TreeIcons.FolderClosed;
                //                node.SelectedImageIndex = (int)TreeIcons.FolderClosed;
                //            }
                //            break;
                //    }
                //}
            }
        }

        protected void SolutionTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node != null && e.Node is SolutionTreeNode)
            {
                var node = e.Node as SolutionTreeNode;
                SelectedNode = node;

                if (node.Type == SolutionTreeNodeTypes.File)
                {
                    var args = new SolutionActionEventArgs {Action = SolutionTreeViewActions.Open, Node = node};
                    OnActionRequest(sender, args);
                }
            }
        }

        #endregion

        #region Bubble events

        public event EventHandler<SolutionActionEventArgs> ActionRequest;

        public void OnActionRequest(object sender, SolutionActionEventArgs e)
        {
            if (ActionRequest != null)
            {
                if (e.Node == null)
                {
                    e.Node = SelectedNode as SolutionTreeNode;
                }
                ActionRequest(sender, e);
            }
        }

        #endregion
    }

    public class SolutionActionEventArgs : EventArgs
    {
        public SolutionTreeViewActions Action = SolutionTreeViewActions.Unknown;
        public SolutionTreeNode Node;

        public SolutionActionEventArgs()
        {
        }

        public SolutionActionEventArgs(SolutionTreeViewActions action)
        {
            Action = action;
        }
    }
}